package com.link510.aitools.core.helper;


import com.blankj.utilcode.util.EncryptUtils;
import com.google.common.base.Strings;
import com.link510.aitools.core.config.AppDefalutConfig;
import com.link510.aitools.services.Commons;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * AES解密
 */
public class AESHelper {


    private static AESHelper mInstance = null;

    //注意: 这里的password(秘钥必须是16位的)
    private final String secretKey;

    /**
     * 字符串算法库
     */
    private final String algorithmStr = "AES/ECB/PKCS5Padding";

    /**
     * 字符集编码
     */
    private Charset defauleCharset = StandardCharsets.UTF_8;


    /**
     * 单例
     *
     * @return AESHelper
     */
    public static AESHelper getInstance() {

        if (mInstance == null) {

            synchronized (AESHelper.class) {

                if (mInstance != null) {
                    return mInstance;
                }

                String secretKey = null;
                try {
                    secretKey = Commons.getInstance().loadMachineInfo().getSecretKey();
                } catch (Exception ex) {
                    secretKey = AppDefalutConfig.getInstance().getSecretKey();
                }
                mInstance = new AESHelper(secretKey);
            }
        }

        return mInstance;
    }

    public AESHelper(String secretKey) {
        this.secretKey = secretKey;
    }

    //region 十六进制加解密

    /**
     * 16进制加密
     *
     * @param content 字符串
     * @return String
     */
    public String encryptAES2HexString(String content) {
        return encryptAES2HexString(string2Bytes(content), this.secretKey, null);
    }

    /**
     * 16进制加密
     *
     * @param content  字符串
     * @param password 密码
     * @param iv       偏移向量
     * @return String
     */
    private String encryptAES2HexString(byte[] content, String password, byte[] iv) {

        try {
            byte[] keyStr = getKey(password);
            return EncryptUtils
                    .encryptAES2HexString(content,
                            keyStr,
                            this.algorithmStr, iv);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }


    /**
     * 16进制解密
     *
     * @param content 字符串
     * @return String
     */
    public String decryptHexStringAES(String content) {
        return decryptHexStringAES(content, this.secretKey, null);
    }

    /**
     * 16进制解密
     *
     * @param content  字符串
     * @param password 密码
     * @param iv       偏移向量
     * @return String
     */
    private String decryptHexStringAES(String content, String password, byte[] iv) {

        try {
            byte[] keyStr = getKey(password);
            byte[] bytes = EncryptUtils
                    .decryptHexStringAES(content,
                            keyStr,
                            this.algorithmStr, iv);

            return bytes2String(bytes);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }


    //endregion


    //region Base64位加解密

    /**
     * Base64位加密
     *
     * @param content 内容
     * @return byte[]
     */
    public byte[] encryptAES2Base64(String content) {
        //加密之后的字节数组,转成16进制的字符串形式输出
        return encryptAES2Base64(content, this.secretKey, null);
    }

    /**
     * Base64位加密
     *
     * @param content  内容
     * @param password 字符串密钥
     * @param iv       偏移向量
     * @return byte[]
     */
    public byte[] encryptAES2Base64(String content,
                                    String password,
                                    byte[] iv) {


        try {

            byte[] keyStr = getKey(password);
            return EncryptUtils
                    .encryptAES2Base64(string2Bytes(content),
                            keyStr,
                            this.algorithmStr, iv);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    /**
     * 16进制解密
     *
     * @param content 字符串
     * @return String
     */
    public byte[] decryptBase64AES(String content) {
        return decryptBase64AES(string2Bytes(content, this.defauleCharset), this.secretKey, null);
    }


    /**
     * 16进制解密
     *
     * @param bytes    字符数组
     * @param password 密码
     * @param iv       偏移向量
     * @return String
     */
    private byte[] decryptBase64AES(byte[] bytes, String password, byte[] iv) {

        try {
            byte[] keyStr = getKey(password);
            return EncryptUtils
                    .decryptBase64AES(bytes,
                            keyStr,
                            this.algorithmStr, iv);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }
    //endregion


    //region 公共函数

    /**
     * 获取密码Key
     *
     * @param password 密钥
     * @return byte[]
     */
    public byte[] getKey(String password) {

        byte[] rByte = null;

        if (Strings.isNullOrEmpty(password)) {
            rByte = new byte[24];
        } else {
            rByte = string2Bytes(password);
        }
        return rByte;
    }

    /**
     * 字符串转byte[]
     *
     * @param content 字符内容
     */
    private byte[] string2Bytes(String content) {
        return string2Bytes(content, this.defauleCharset);
    }

    /**
     * 字符串转byte[]
     *
     * @param content        字符内容
     * @param defauleCharset 字符集
     */
    private byte[] string2Bytes(String content, Charset defauleCharset) {

        try {

            if (defauleCharset == null) {
                defauleCharset = this.defauleCharset;
            }

            return content.getBytes(defauleCharset);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return new byte[0];

    }

    /**
     * byte[]转字符串
     *
     * @param bytes 字符内容
     */
    private String bytes2String(byte[] bytes) {
        return bytes2String(bytes, this.defauleCharset);
    }


    /**
     * byte[]转字符串
     *
     * @param bytes 字符内容
     */
    private String bytes2String(byte[] bytes, Charset defauleCharset) {

        try {

            if (defauleCharset == null) {
                defauleCharset = this.defauleCharset;
            }

            return new String(bytes, defauleCharset);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    //endregion
}
